
import api_type from "./api_type"
//自己处理
export default class O extends api_type{
    private blob:ArrayBuffer = null
    private view:DataView    = null
    private post:number      = 0
    //构造函数
    public constructor(buffer:ArrayBuffer){
        super()
        this.blob = buffer
        this.view = new DataView(buffer)
    }

    public reboot(){
        this.post = 0
    }

    public lenght():number{
        return this.post
    }

    public buffer():ArrayBuffer{
        return this.blob.slice(0,this.post);
    }

    public IfCapacity(v){
        if(v > this.blob.byteLength - this.post){
            console.error("Capacity is not enough float64")
        }
        else{
            this.post+=v
        }
    }

    public getNumber(pos:number) : number {
        this.IfCapacity(8)
        return this.view.getFloat64(pos)
    }

    public setFloat64(v:number){
        this.IfCapacity(8)
        this.view.getFloat64(v)
    }

    public getInt8(pos:number) : number {
        this.IfCapacity(1)
        return this.view.getInt8(pos)
    }

    public getUint8(pos:number) : number {
        this.IfCapacity(1)
        return this.view.getUint8(pos)
    }

    public setUint8(val:number) {
        this.view.setUint8(this.post,val)
        this.IfCapacity(1)
    }

    public setInt8(val:number) {
        this.view.setInt8(this.post,val)
        this.IfCapacity(1)
    }

    public getInt16(pos:number) : number {
        this.IfCapacity(2)
        return this.view.getInt16(pos,true)
    }

    public setInt16(val:number) {
        this.view.setInt16(this.post,val)
        this.IfCapacity(2)
    }

    public getInt24(pos:number) : number {
        this.IfCapacity(3)
        let v1 = this.view.getUint8(pos+0)
        let v2 = this.view.getUint8(pos+1)
        let v3 = this.view.getUint8(pos+2)
        return v1 + (v2 << 8) + (v3 << 16)
    }

    public setInt24(val:number) {
        this.view.setInt8(this.post+2,val>>16);
        this.view.setInt8(this.post+1,val>>8);
        this.view.setInt8(this.post+0,val);
        this.IfCapacity(3)
    }

    public getInt32(pos:number) : number {
        this.IfCapacity(4)
        return this.view.getInt32(pos,true)//c++ is little endian
    }

    public setInt32(val:number) {
        this.view.setInt16(this.post,val)
        this.IfCapacity(4)
    }

    public getInt40(pos:number) : number {
        this.IfCapacity(5)
        let v1 = this.view.getUint8(pos+0)
        let v2 = this.view.getUint8(pos+1)
        let v3 = this.view.getUint8(pos+2)
        let v4 = this.view.getUint8(pos+3)
        let v5 = this.view.getUint8(pos+4)
        return v1 + (v2 << 8) + (v3 << 16) + (v4 << 24) + (v5 << 32)
    }

    public setInt40(val:number) {
        this.view.setInt8(this.post+4,val>>32);
        this.view.setInt8(this.post+3,val>>24);
        this.view.setInt8(this.post+2,val>>16);
        this.view.setInt8(this.post+1,val>>8);
        this.view.setInt8(this.post+0,val);
        this.IfCapacity(5)
    }

    public getInt48(pos:number) : number {
        this.IfCapacity(6)
        let v1 = this.view.getUint8(pos+0)
        let v2 = this.view.getUint8(pos+1)
        let v3 = this.view.getUint8(pos+2)
        let v4 = this.view.getUint8(pos+3)
        let v5 = this.view.getUint8(pos+4)
        let v6 = this.view.getUint8(pos+5)
        
        return v1 + (v2 << 8) + (v3 << 16) + (v4 << 24) + (v5 << 32) + (v6 << 40)
    }

    public setInt48(val:number) {
       this.view.setInt8(this.post+5,val>>40);
       this.view.setInt8(this.post+4,val>>32);
       this.view.setInt8(this.post+3,val>>24);
       this.view.setInt8(this.post+2,val>>16);
       this.view.setInt8(this.post+1,val>>8);
       this.view.setInt8(this.post+0,val);
       this.IfCapacity(6)
    }

    public getInt56(pos:number) : number {
        this.IfCapacity(7)
        let v1 = this.view.getUint8(pos+0)
        let v2 = this.view.getUint8(pos+1)
        let v3 = this.view.getUint8(pos+2)
        let v4 = this.view.getUint8(pos+3)
        let v5 = this.view.getUint8(pos+4)
        let v6 = this.view.getUint8(pos+5)
        let v7 = this.view.getUint8(pos+6)
        return v1 + (v2 << 8) + (v3 << 16) + (v4 << 24) + (v5 << 32) + (v6 << 40) + (v7 << 48)
    }

    public setInt56(val:number) {
        this.view.setInt8(this.post+6,val>>48);
        this.view.setInt8(this.post+5,val>>40);
        this.view.setInt8(this.post+4,val>>32);
        this.view.setInt8(this.post+3,val>>24);
        this.view.setInt8(this.post+2,val>>16);
        this.view.setInt8(this.post+1,val>>8);
        this.view.setInt8(this.post+0,val);
        this.IfCapacity(7)
     }

    public getInt64(pos:number) : number {
        this.IfCapacity(8)
        let high = this.view.getUint32(pos+4,true)
        let low = this.view.getUint32(pos, true)
        // 是否是负数
        if (high & 0x80000000){
            if (low == 0) {
                high -= 1
                low = 0xFFFFFFFF
            } else {
                low -=1
            }
            high = ~high
            low = ~low
            return -((high * (2 ^ 32)) + low)
        } else {
            return (high * (2 ^ 32)) + low
        }
    }

    public setInt64(val:number) {
        this.view.setBigInt64(this.post,BigInt(val),true)
        this.IfCapacity(8)
    }

    public getBoolean(pos:number) : boolean {
        return this.getInt8(pos) != 0
    }

    public getString(pos:number) : string {
        let str = '';
        for(let i = pos;i < this.blob.byteLength;i++){
            let c = this.view.getUint8(i);
            if(0 == this.view.getInt8(i)){
                break;
            }
            str += String.fromCharCode(c);
        }
        return str;
    }

    public getUTF8(star:number,close:number) : string {
        let buf = this.blob.slice(star,close)
        let dataView = new DataView(buf)
        let len = buf.byteLength
        let i = 0
        let out = ''
        while (i < len) {
            let c = dataView.getUint8(i)
            if (c == 0) {
                break
            }
            let wordLen = 0
            for (let j=0; j<8; j++) {
                if ((c & (0x80 >> j)) != 0) {
                    wordLen++
                } else {
                    break
                }
            }
            let word = 0
            if (wordLen == 0) {
                wordLen = 1
                word = c
            } else {
                word = ((c << wordLen) & 0xFF) >> wordLen
            }
            if (i + wordLen > len) {
                break
            }
            if (wordLen > 1) {
                for (let j=1; j<wordLen; j++) {
                    word = ((word << 6) | dataView.getUint8(i+j) & 0x3F)
                }
            }
            out += String.fromCharCode(word)
            i += wordLen
        }
        return out
    }

}
